package filecopy;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class Window implements Iterable<FCpacket> {

    private Queue<FCpacket> window = new LinkedList<>();
    private int windowSize;
    private FileCopyClient fcc;

    Window(int windowSize, FileCopyClient fcc) {
        this.windowSize = windowSize;
        this.fcc = fcc;
    }

    public synchronized int size() {
        return window.size();
    }

    public synchronized void add(FCpacket pkt) {
        while (this.size() == windowSize) {
            try {
                wait();
            } catch (InterruptedException ex) {
                return;
            }
        }

        window.add(pkt);
    }

    public synchronized void remove() {
        FCpacket p = window.remove();
        System.out.println("Packet removed " + p.getSeqNum());
        notify();
    }

    //TODO prüfen, ob hier der Iterator iwie synchonisiert werden muss...
    @Override
    public Iterator<FCpacket> iterator() {
        return window.iterator();
    }

    public synchronized void setAckTrue(long seqNr) {
        for (FCpacket packet : window) {
            if (packet.getSeqNum() == seqNr) {
                packet.setValidACK(true);
                fcc.cancelTimer(packet);
                break;
            }
        }

        System.out.println("SetACK[" + seqNr + "] top:" + (window.isEmpty() ? "[]" : window.peek().getSeqNum()));
        while (!window.isEmpty() && window.peek().isValidACK()) {
            this.remove();
        }
    }

    public synchronized FCpacket getBySequenceNumber(long seqNr) {
        for (FCpacket p : window) {
            if (p.getSeqNum() == seqNr) {
                return p;
            }
        }

        return null;
    }

    public synchronized void waitForEmptyWindow() {
        try {
            while (!window.isEmpty()) {
                wait();
            }
        } catch (InterruptedException ex) {
            return;
        }
    }

    @Override
    public String toString() {
        return window.toString();
    }
}
